{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ULndVKL12doD"
      },
      "source": [
        "##### Copyright 2019 Google LLC.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "both",
        "colab": {},
        "colab_type": "code",
        "id": "FhqgxELZ2jTB"
      },
      "outputs": [],
      "source": [
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "yz0yBU27ED67"
      },
      "source": [
        "# On Variational Bounds of Mutual Information\n",
        "Ben Poole, Sherjil Ozair, A\u0026auml;ron van den Oord, Alexander A. Alemi, George Tucker\u003cbr/\u003e\n",
        "*ICML 2019*\u003cbr/\u003e\n",
        "[paper](https://arxiv.org/abs/1905.06922) / [slides](https://docs.google.com/presentation/d/1dz0AVBy6VDz7SU43m0IQjuJDviEuf3NpWSeIWov_DYc/present?usp=sharing) / [video](https://www.facebook.com/icml.imls/videos/2202320806483370/?t=2562) / [poster](https://drive.google.com/file/d/1C5ZYqSJRaOupQelqYgVbc9lJ7__0CDXA/view?usp=sharing)\n",
        "\n",
        "This notebook contains code for most of the variational bounds on mutual information presented in the paper, and experiments on the toy Gaussian problem. \n",
        "\n",
        "Comments? Complaints? Questions? Bug Ben on Twitter [@poolio](https://twitter.com/poolio)\n",
        "\n",
        "\u003csup\u003eThanks to [Zhe Dong](https://www.linkedin.com/in/hoogendong/) for valuable feedback on this colab.\u003c/sup\u003e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "IfHEX-0eaOHP"
      },
      "source": [
        "### Introduction\n",
        "\n",
        "Here we give a brief overview of the challenges of MI estimation and a few of the variational bounds we presented in the paper. Please checkout the [paper](https://arxiv.org/abs/1905.06922) for more details.\n",
        "\n",
        "Our goal is to build efficient estimators of mutual information (MI) that leverage neural networks. Mutual information is given by:\n",
        "$$I(X; Y) = \\mathbb{E}_{p(x,y)}\\left[\\log \\frac{p(x,y)}{p(x)p(y)}\\right].$$\n",
        "Estimating MI is challenging as we often only have access to samples $x, y$ but do not know the densities.\n",
        "\n",
        "To overcome these challenges, we review and presented several variational estimators of MI. These estimators replace the intractable MI objective with a tractable objective that lower or upper bounds MI, and depends on neural-network-powered critics and baselines. For example, the $I_\\text{NWJ}$ bound is given by:\n",
        "\n",
        "$$ I(X; Y) \\ge 1 + \\mathbb{E}_{p(x, y)} \\left[\\color{blue} f(x,y) \\right] - \\mathbb{E}_{p(x)p(y)} \\left[  \\exp{{\\color{blue} f(x , y)}}\\right] $$\n",
        "where $\\color{blue} f$ is a neural network that takes $x$ and $y$ as input and outputs a scalar.\n",
        "\n",
        "Below, we code up several variational lower and upper bounds on mutual information:\n",
        "- Existing lower bounds: $I_\\text{NWJ}, \\,I_\\text{InfoNCE}$\n",
        "- New lower bounds: $I_\\text{TUBA},\\, I_{\\alpha},\\, I_\\text{JS}$\n",
        "- Structured lower bound ($I_\\text{TNCE}$) and upper bounds ($I_\\text{BA}$, $I_\\text{MBU}$) with known $p(y|x)$\n",
        "\n",
        "Here's a table of the bounds we'll code up here as well as the mathematical objectives:\n",
        "![Table of MI bounds](https://i.imgur.com/pvZtPLl.png)\n",
        "\n",
        "We apply these bounds to a toy problem, where $(x, y)$ are jointly Gaussian, and we vary the correlation between $x$ and $y$ over time to increase the mutual information. For the bounds with neural network critics, we train the critics to tighten the variational bounds.\n",
        "\n",
        "### Practical suggestions\n",
        "- MI estimates with neural networks are highly sensitive to the representation of the input data, architecture, optimizer, and more. When applying these estimators to new datasets, you will need to experiment!\n",
        "- For representation learning, the $I_\\text{NCE}$ bounds are a good place to start. Implementing them is simple.\n",
        "- For estimation, start with the $I_\\alpha$ bounds with a small $\\alpha$. The implementation is trickier, but they can greatly reduce variance vs. $I_\\text{NWJ}$.\n",
        "- If you have known structure use it. For example, if you know a conditional distribution $p(y|x)$, use one of the structured bounds. \n",
        "\n",
        "### Implementation notes:\n",
        "- For most bounds, we will work with a matrix, denoted by `f` or `scores` that contains the output of the critic for every pair of elements in the minibatch: `scores[i, j] = critic(x[j], y[i])`\n",
        "- Most variational lower bounds on MI require samples from both the joint $p(x, y)$ and marginal distributions $p(x)p(y)$. For a minibatch of size $K$, we have $K$ samples from the joint $p(x,y)$ and can form samples from the marginal by using all pairs $x_i, y_j$ where $i \\ne j$, giving $K \\times (K -1)$ samples from the marginal. The diagonal elements of the `scores` matrix correspond to the $K$ critic scores for samples from the joint, and the off-diagonal elements correspond to the critic scores for samples from the marginal.\n",
        "- In this notebook we assume that we use all other elements in the minibatch as negative samples. For certain InfoMax tasks, for example when negatives come from the same image but at other spatial locations, one has to be more careful about summing over and selecting the right positive and negative examples to form the two expectations.\n",
        "- Separable critics are the more efficient and popular architecture. Instead of having to do $K^2$ forward passes, you only have to do $2 \\times K$ followed by an inner product. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "KgnZ2S_KF5-y"
      },
      "source": [
        "## Setup\n",
        "Notebook should work in TF 1.X, but uses Eager-mode."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "L5Qe4JE48CNO"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "import tensorflow as tf\n",
        "tf.enable_eager_execution()\n",
        "\n",
        "import tensorflow_probability as tfp\n",
        "tfd = tfp.distributions\n",
        "tfkl = tf.keras.layers\n",
        "tfp = tfp.layers\n",
        "\n",
        "import pandas as pd # used for exponential moving average\n",
        "from scipy.special import logit\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vJXJN6s7aY-p"
      },
      "source": [
        "## Variational bound implementations\n",
        "###  TUBA and NWJ lower bounds\n",
        "The $I_\\text{TUBA}$ variational lower bound on mutual information is given by:\n",
        "$$ I(X; Y) \\ge 1 + \\mathbb{E}_{p(x, y)} \\left[\\log {e^{\\color{blue} f(x,y)}\\over{\\color{green}  a(y)}} \\right] - \\mathbb{E}_{p(x)p(y)} \\left[  \\frac{e^{{\\color{blue} f(x , y)}}}{\\color{green} a(y)}\\right] \\triangleq I_\\text{TUBA}$$\n",
        "These bounds can be low bias, but are typically high variance. To implement this bound, we need the critic scores for all elements in the minibatch: `scores[i, j] = critic(x[i], y[j])`, and the value of the baseline `a[j] = baseline(y[j])` for every `y`. Instead of requiring the baseline to be non-negative, we assume that the argument passed in is $\\log {\\color{green} a(y)}$, and will exponentiate it to get the baseline ${\\color{green} a(y)}$.\n",
        "\n",
        "The implementation requires averaging the exponentiated critic over all independent samples, corresponding to the off-diagonal terms in `scores`,  which is done by the `reduce_logmeanexp_nodiag` function.\n",
        "\n",
        "The $I_\\text{NWJ}$ bound just uses the constant $e$ for the baseline, which is equivalent to adding 1 to the critic scores."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "uE0-b7dreyFB"
      },
      "outputs": [],
      "source": [
        "def reduce_logmeanexp_nodiag(x, axis=None):\n",
        "  batch_size = x.shape[0].value\n",
        "  logsumexp = tf.reduce_logsumexp(x - tf.linalg.tensor_diag(np.inf * tf.ones(batch_size)), axis=axis)\n",
        "  if axis:\n",
        "    num_elem = batch_size - 1.\n",
        "  else:\n",
        "    num_elem  = batch_size * (batch_size - 1.)\n",
        "  return logsumexp - tf.math.log(num_elem)\n",
        "\n",
        "def tuba_lower_bound(scores, log_baseline=None):\n",
        "  if log_baseline is not None:\n",
        "    scores -= log_baseline[:, None]\n",
        "  batch_size = tf.cast(scores.shape[0], tf.float32)\n",
        "  # First term is an expectation over samples from the joint,\n",
        "  # which are the diagonal elmements of the scores matrix.\n",
        "  joint_term = tf.reduce_mean(tf.linalg.diag_part(scores))\n",
        "  # Second term is an expectation over samples from the marginal,\n",
        "  # which are the off-diagonal elements of the scores matrix.\n",
        "  marg_term = tf.exp(reduce_logmeanexp_nodiag(scores))\n",
        "  return 1. + joint_term -  marg_term\n",
        "\n",
        "def nwj_lower_bound(scores):\n",
        "  # equivalent to: tuba_lower_bound(scores, log_baseline=1.)\n",
        "  return tuba_lower_bound(scores - 1.) "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "DUd0hFZ5Js8k"
      },
      "source": [
        "### InfoNCE contrastive lower bound\n",
        "The InfoNCE variational lower bound is the easiest to implement, and typically provides low variance but high bias estimates of MI:\n",
        "$$I(X; Y) \\ge \\mathbb{E}_{p^K(x,y)}\\left[\\frac{1}{K} \\sum_{i=1}^K \\log \\frac{e^{\\color{blue}f(x_i, y_i)}}{\\frac{1}{K}\\sum_{j=1}^K e^{\\color{blue} f(x_j, y_i)}}\\right].$$\n",
        "The expectation $p^K(x,y)$ draws $K$ samples from the joint $(x, y)$. So for a minibatch of $K$ examples, we are effectively forming a single sample Monte-Carlo estimate of the quantity inside the expectation.\n",
        "\n",
        "Here we use `reduce_logsumexp` so the implementation matches the math, but you can also implement this with `sparse_softmax_cross_entropy_with_logits` using a different label for each of the `K` elements in the minibatch."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "rKEhwRbMd81i"
      },
      "outputs": [],
      "source": [
        "def infonce_lower_bound(scores):\n",
        "  \"\"\"InfoNCE lower bound from van den Oord et al. (2018).\"\"\"\n",
        "  nll = tf.reduce_mean(tf.linalg.diag_part(scores) - tf.reduce_logsumexp(scores, axis=1))\n",
        "  # Alternative implementation:\n",
        "  # nll = -tf.nn.sparse_softmax_cross_entropy_with_logits(logits=scores, labels=tf.range(batch_size))\n",
        "  mi = tf.math.log(tf.cast(scores.shape[0].value, tf.float32)) + nll\n",
        "  return mi"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wluSdg-QLCfJ"
      },
      "source": [
        "### Interpolated lower bounds\n",
        "The interpolated lower bounds are the trickiest to implement, but also provide the best of both worlds: lower bias or variance relative to the NWJ and InfoNCE bounds. We start with the multisample TUBA bound from the paper:\n",
        "$$I(X_1; Y) \\geq 1+\\mathbb{E}_{p(x_{1:K})p(y|x_1)}\\left[\\log \\frac{e^{f(x_1,y)}}{a(y; x_{1:K})}\\right]\n",
        "- \\mathbb{E}_{p(x_{1:K})p(y)}\\left[ \\frac{e^{f(x_1,y)}}{a(y; x_{1:K})}\\right]$$\n",
        "Coding up this bound is tricky as we need $K+1$ samples from the joint $p(x,y)$: $K$ of these samples are used for the first term, and the additional sample is used for the independent sample from $p(y)$ for the second term. In the minibatch setting, we can implement this by holding out the $j$th sample from the joint,  and using $y_j$ for the indepent sample from $p(y)$ for the second term, and $x_\\ne j$ (all elements in the minibatch except element $j$) for the samples from $p(x_{1:K})$. A single-sample Monte-Carlo approximation to the NWJ bound is then given by:\n",
        "\n",
        "$$1 + \\log \\frac{e^{f(x_1, y_1)}}{a(y_1; x_{\\ne j}, \\alpha)} - \\frac{e^{f(x_1, y_j)}}{a(y_j; x_{\\ne j}, \\alpha)}$$\n",
        "Instead of just using $(x_1, y_1)$ as the only positive example, we can use all samples from the joint in the minibatch: $(x_i, y_i)$. Summing over the $K$ elements which are not the element we are holding out for the second expectation ($y_j$), yields:\n",
        "$$1 + \\frac{1}{K}\\sum_{i\\ne j} \\left(\\log \\frac{e^{f(x_i, y_i)}}{a(y_i; x_{\\ne j}, \\alpha)} - \\frac{e^{f(x_i, y_j)}}{a(y_j; x_{\\ne j}, \\alpha)}\\right)$$\n",
        "\n",
        "Furthermore, in the minibatch setting we can choose any element in the minibatch to hold out for the second expectation. Summing over all possible (leave one out) combinations yields:\n",
        "$$1 + \\frac{1}{K+1} \\sum_{j=1}^{K+1} \\frac{1}{K}\\sum_{i\\ne j} \\left(\\log \\frac{e^{f(x_i, y_i)}}{a(y_i; x_{\\ne j}, \\alpha)} - \\frac{e^{f(x_i, y_j)}}{a(y_j; x_{\\ne j}, \\alpha)}\\right)$$\n",
        "where the interpolated baseline is given by $a(y; x_{1:M}) = \\alpha \\frac{1}{K} \\sum_{l=1}^K e^{f(x_l, y)} + (1-\\alpha) q(y)$. We work in log-space for numerical stability, using `compute_log_loomean` to compute the leave one out InfoNCE baselines, and `log_interpolate` to compute the log baseline for the interpolated bound."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "V7IME_GqLGHe"
      },
      "outputs": [],
      "source": [
        "def log_interpolate(log_a, log_b, alpha_logit):\n",
        "  \"\"\"Numerically stable implementation of log(alpha * a + (1-alpha) * b).\"\"\"\n",
        "  log_alpha = -tf.nn.softplus(-alpha_logit)\n",
        "  log_1_minus_alpha = -tf.nn.softplus(alpha_logit)\n",
        "  y = tf.reduce_logsumexp(tf.stack((log_alpha + log_a, log_1_minus_alpha + log_b)), axis=0)\n",
        "  return y\n",
        "\n",
        "def compute_log_loomean(scores):\n",
        "  \"\"\"Compute the log leave-one-out mean of the exponentiated scores.\n",
        "\n",
        "  For each column j we compute the log-sum-exp over the row holding out column j.\n",
        "  This is a numerically stable version of:\n",
        "  log_loosum = scores + tfd.softplus_inverse(tf.reduce_logsumexp(scores, axis=1, keepdims=True) - scores) \n",
        "  Implementation based on tfp.vi.csiszar_divergence.csiszar_vimco_helper.\n",
        "  \"\"\"\n",
        "  max_scores = tf.reduce_max(scores, axis=1, keepdims=True)\n",
        "  lse_minus_max = tf.reduce_logsumexp(scores - max_scores, axis=1, keepdims=True)\n",
        "  d = lse_minus_max + (max_scores - scores)\n",
        "  d_ok = tf.not_equal(d, 0.)\n",
        "  safe_d = tf.where(d_ok, d, tf.ones_like(d))\n",
        "  loo_lse = scores + tfd.softplus_inverse(safe_d)\n",
        "  # Normalize to get the leave one out log mean exp\n",
        "  loo_lme = loo_lse - tf.math.log(scores.shape[1].value - 1.)\n",
        "  return loo_lme\n",
        "\n",
        "def interpolated_lower_bound(scores, baseline, alpha_logit):\n",
        "  \"\"\"Interpolated lower bound on mutual information.\n",
        "\n",
        "  Interpolates between the InfoNCE baseline ( alpha_logit -\u003e -infty),\n",
        "  and the single-sample TUBA baseline (alpha_logit -\u003e infty)\n",
        "\n",
        "  Args:\n",
        "    scores: [batch_size, batch_size] critic scores\n",
        "    baseline: [batch_size] log baseline scores\n",
        "    alpha_logit: logit for the mixture probability\n",
        "\n",
        "  Returns:\n",
        "    scalar, lower bound on MI\n",
        "  \"\"\"\n",
        "  batch_size = scores.shape[0].value\n",
        "  # Compute InfoNCE baseline\n",
        "  nce_baseline = compute_log_loomean(scores)\n",
        "  # Inerpolated baseline interpolates the InfoNCE baseline with a learned baseline\n",
        "  interpolated_baseline = log_interpolate(\n",
        "      nce_baseline, tf.tile(baseline[:, None], (1, batch_size)), alpha_logit)\n",
        "  # Marginal term.\n",
        "  critic_marg = scores - tf.linalg.diag_part(interpolated_baseline)[:, None]\n",
        "  marg_term = tf.exp(reduce_logmeanexp_nodiag(critic_marg))\n",
        "\n",
        "  # Joint term.\n",
        "  critic_joint = tf.linalg.diag_part(scores)[:, None] - interpolated_baseline\n",
        "  joint_term = (tf.reduce_sum(critic_joint) -\n",
        "                tf.reduce_sum(tf.linalg.diag_part(critic_joint))) / (batch_size * (batch_size - 1.))\n",
        "  return 1 + joint_term  - marg_term"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mGptVHXy63NE"
      },
      "source": [
        "### JS-KL hybrid lower bound\n",
        "We can also use different approaches for training the critic vs. estimating mutual informaiton. The $I_\\text{JS}$ bound just trains the critic with the standard lower bound on the Jensen-Shannon divergence used in GANs, and then evaluates the critic using the $I_\\text{NWJ}$ lower bound on KL (mutual information). \n",
        "\n",
        "We use a fun trick to simplify the code here:\n",
        "`z = x + tf.stop_gradient(y - x)`.\u003cbr/\u003e\n",
        "`z` gives the value of `y` on the forward pass, but the gradient of `x` on the backward pass."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "GdyDZ8Tt66Dy"
      },
      "outputs": [],
      "source": [
        "def js_fgan_lower_bound(f):\n",
        "  \"\"\"Lower bound on Jensen-Shannon divergence from Nowozin et al. (2016).\"\"\"\n",
        "  f_diag = tf.linalg.tensor_diag_part(f)\n",
        "  first_term = tf.reduce_mean(-tf.nn.softplus(-f_diag))\n",
        "  n = tf.cast(f.shape[0], tf.float32)\n",
        "  second_term = (tf.reduce_sum(tf.nn.softplus(f)) - tf.reduce_sum(tf.nn.softplus(f_diag))) / (n * (n - 1.))\n",
        "  return first_term - second_term\n",
        "\n",
        "def js_lower_bound(f):\n",
        "  \"\"\"NWJ lower bound on MI using critic trained with Jensen-Shannon.\n",
        "\n",
        "  The returned Tensor gives MI estimates when evaluated, but its gradients are\n",
        "  the gradients of the lower bound of the Jensen-Shannon divergence.\"\"\"\n",
        "  js = js_fgan_lower_bound(f)\n",
        "  mi = nwj_lower_bound(f)\n",
        "  return js + tf.stop_gradient(mi - js)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wOraxkkSOb-6"
      },
      "source": [
        "### Structured Bounds\n",
        "\n",
        "See the end of the notebook for code for the structured bounds. The implementation when using these bounds is often different, as we use a known conditional distribution $p(y|x)$ instead of a critic function $f(x, y)$ that scores all pairs of points. For simplicity, we will just demonstrate the minibatch lower bound $I_\\text{TNCE}$, which is equivalent to $I_\\text{NCE}$ but using the critic $f(x,y) = \\log p(y|x)$. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Iu6lcSGvN5cs"
      },
      "source": [
        "### Putting it together"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "kobSvpv6N4SZ"
      },
      "outputs": [],
      "source": [
        "def estimate_mutual_information(estimator, x, y, critic_fn,\n",
        "                                baseline_fn=None, alpha_logit=None):\n",
        "  \"\"\"Estimate variational lower bounds on mutual information.\n",
        "\n",
        "  Args:\n",
        "    estimator: string specifying estimator, one of:\n",
        "      'nwj', 'infonce', 'tuba', 'js', 'interpolated'\n",
        "    x: [batch_size, dim_x] Tensor\n",
        "    y: [batch_size, dim_y] Tensor\n",
        "    critic_fn: callable that takes x and y as input and outputs critic scores\n",
        "      output shape is a [batch_size, batch_size] matrix\n",
        "    baseline_fn (optional): callable that takes y as input \n",
        "      outputs a [batch_size]  or [batch_size, 1] vector\n",
        "    alpha_logit (optional): logit(alpha) for interpolated bound\n",
        "\n",
        "  Returns:\n",
        "    scalar estimate of mutual information\n",
        "  \"\"\"\n",
        "  scores = critic_fn(x, y)\n",
        "  if baseline_fn is not None:\n",
        "    # Some baselines' output is (batch_size, 1) which we remove here.\n",
        "    log_baseline = tf.squeeze(baseline_fn(y))\n",
        "  if estimator == 'infonce':\n",
        "    mi = infonce_lower_bound(scores)\n",
        "  elif estimator == 'nwj':\n",
        "    mi = nwj_lower_bound(scores)\n",
        "  elif estimator == 'tuba':\n",
        "    mi = tuba_lower_bound(scores, log_baseline)\n",
        "  elif estimator == 'js':\n",
        "    mi = js_lower_bound(scores)\n",
        "  elif estimator == 'interpolated':\n",
        "    assert alpha_logit is not None, \"Must specify alpha_logit for interpolated bound.\"\n",
        "    mi = interpolated_lower_bound(scores, log_baseline, alpha_logit)\n",
        "  return mi"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "r-wyBXaODvL7"
      },
      "source": [
        "## Neural network architectures\n",
        "\n",
        "**Critics**: we consider two choices of neural network architectures for $\\color{blue} f(x,y)$:\n",
        "1. **Separable**: $f(x,y) = g(x)^Th(y)$ where $g$ and $h$ are two different MLPs\n",
        "2. **Concat**: $f(x,y) = g([x, y])$ where we concatenate $x$ and $y$ and feed them into a single MLP\n",
        "\n",
        "Using a separable baseline is typically more efficient, as you only have to do `batch_size` forward passes through each network vs. the `batch_size * batch_size` with the concat critic.\n",
        "\n",
        "**Baselines**: we consider three possibilities for the baseline $\\color{green}a(y)$:\n",
        "1. **Constant**: $a(y)$ is a fixed constant (as in $I_\\text{NWJ}$)\n",
        "2. **Unnormalized**: $a(y)$ is a neural network that produces a scalar output (representing $\\log a(y)$)\n",
        "3. **Gaussian**: $a(y)$ is a Gaussian distribution. Here we fix the mean and variance to be 1, but you could use any tractable density with learnable parameters as well."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "LwSIGeXlD11E"
      },
      "source": [
        "### Critics"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "D7KNSf6kAhVD"
      },
      "outputs": [],
      "source": [
        "def mlp(hidden_dim, output_dim, layers, activation):\n",
        "  return tf.keras.Sequential(\n",
        "      [tfkl.Dense(hidden_dim, activation) for _ in range(layers)] +\n",
        "      [tfkl.Dense(output_dim)])\n",
        "   \n",
        "\n",
        "class SeparableCritic(tf.keras.Model):\n",
        "  def __init__(self, hidden_dim, embed_dim, layers, activation, **extra_kwargs):\n",
        "    super(SeparableCritic, self).__init__()\n",
        "    self._g = mlp(hidden_dim, embed_dim, layers, activation)\n",
        "    self._h = mlp(hidden_dim, embed_dim, layers, activation)\n",
        "\n",
        "  def call(self, x, y):\n",
        "    scores = tf.matmul(self._h(y), self._g(x), transpose_b=True)\n",
        "    return scores\n",
        "\n",
        "\n",
        "class ConcatCritic(tf.keras.Model):\n",
        "  def __init__(self, hidden_dim, layers, activation, **extra_kwargs):\n",
        "    super(ConcatCritic, self).__init__()\n",
        "    # output is scalar score\n",
        "    self._f = mlp(hidden_dim, 1, layers, activation)\n",
        "\n",
        "  def call(self, x, y):\n",
        "    batch_size = tf.shape(x)[0]\n",
        "    # Tile all possible combinations of x and y\n",
        "    x_tiled = tf.tile(x[None, :],  (batch_size, 1, 1))\n",
        "    y_tiled = tf.tile(y[:, None],  (1, batch_size, 1))\n",
        "    # xy is [batch_size * batch_size, x_dim + y_dim]\n",
        "    xy_pairs = tf.reshape(tf.concat((x_tiled, y_tiled), axis=2), [batch_size * batch_size, -1])\n",
        "    # Compute scores for each x_i, y_j pair.\n",
        "    scores = self._f(xy_pairs) \n",
        "    return tf.transpose(tf.reshape(scores, [batch_size, batch_size]))\n",
        "\n",
        "\n",
        "def gaussian_log_prob_pairs(dists, x):\n",
        "  \"\"\"Compute log probability for all pairs of distributions and samples.\"\"\"\n",
        "  mu, sigma = dists.mean(), dists.stddev()\n",
        "  sigma2 = sigma**2\n",
        "  normalizer_term = tf.reduce_sum(-0.5 * (np.log(2. * np.pi) + 2.0 *  tf.math.log(sigma)), axis=1)[None, :]\n",
        "  x2_term = -tf.matmul(x**2, 1.0 / (2 * sigma2), transpose_b=True)\n",
        "  mu2_term = - tf.reduce_sum(mu**2 / (2 * sigma2), axis=1)[None, :]\n",
        "  cross_term = tf.matmul(x, mu / sigma2, transpose_b=True)\n",
        "  log_prob = normalizer_term + x2_term + mu2_term + cross_term\n",
        "  return log_prob\n",
        "\n",
        "  \n",
        "def build_log_prob_conditional(rho, **extra_kwargs):\n",
        "  \"\"\"True conditional distribution.\"\"\"\n",
        "  def log_prob_conditional(x, y):\n",
        "    mu = x * rho\n",
        "    q_y = tfd.MultivariateNormalDiag(mu, tf.ones_like(mu) * tf.cast(tf.sqrt(1.0 - rho**2), tf.float32))\n",
        "    return gaussian_log_prob_pairs(q_y, y)\n",
        "  return log_prob_conditional\n",
        "  \n",
        "\n",
        "CRITICS = {\n",
        "    'separable': SeparableCritic,\n",
        "    'concat': ConcatCritic,\n",
        "    'conditional': build_log_prob_conditional,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "YUuCpQG1D4Ei"
      },
      "source": [
        "### Baselines"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "kDq3q7iZXCk2"
      },
      "outputs": [],
      "source": [
        "def log_prob_gaussian(x):\n",
        "  return tf.reduce_sum(tfd.Normal(0., 1.).log_prob(x), -1)\n",
        "\n",
        "BASELINES= {\n",
        "    'constant': lambda: None,\n",
        "    'unnormalized': lambda: mlp(hidden_dim=512, output_dim=1, layers=2, activation='relu'),\n",
        "    'gaussian': lambda: log_prob_gaussian,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mrbYIKjEXye3"
      },
      "source": [
        "## Experiments"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "T8mMQ1djD7qH"
      },
      "source": [
        "### Dataset: correlated Gaussian\n",
        "We experiment with a super simple correlated Gaussian dataset:\n",
        "\\begin{align}\n",
        "x \u0026\\sim \\mathcal{N}(0, I_d)\\\\\n",
        "y \u0026\\sim \\mathcal{N}(\\rho x, (1 - \\rho^2) I_d)\n",
        "\\end{align}\n",
        "where $d$ is the dimensionality, and $\\rho$ is the correlation. Each pair of dimensions $(x_i, y_i)$ has correlation $\\rho$, and correlation 0 with all other dimensions. We can control the information by varying the correlation $\\rho$:\n",
        "$$I(X; Y) = -\\frac{d}{2} \\log \\left(1 - \\rho^2\\right)$$"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "B5L2rjiLLcFZ"
      },
      "outputs": [],
      "source": [
        "def sample_correlated_gaussian(rho=0.5, dim=20, batch_size=128):\n",
        "  \"\"\"Generate samples from a correlated Gaussian distribution.\"\"\"\n",
        "  x, eps = tf.split(tf.random.normal((batch_size, 2 * dim)), 2, axis=1)\n",
        "  y = rho * x + tf.sqrt(tf.cast(1. - rho**2, tf.float32)) * eps\n",
        "  return x, y\n",
        "\n",
        "def rho_to_mi(dim, rho):\n",
        "  return -0.5  * np.log(1-rho**2) * dim\n",
        "\n",
        "def mi_to_rho(dim, mi):\n",
        "  return np.sqrt(1-np.exp(-2.0 / dim * mi))\n",
        "\n",
        "def mi_schedule(n_iter):\n",
        "  \"\"\"Generate schedule for increasing correlation over time.\"\"\"\n",
        "  mis = np.round(np.linspace(0.5, 5.5-1e-9, n_iter)) *2.0#0.1\n",
        "  return mis.astype(np.float32)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "colab": {
          "height": 229
        },
        "colab_type": "code",
        "executionInfo": {
          "elapsed": 3215,
          "status": "ok",
          "timestamp": 1561485649269,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "do1lJdz9P3aY",
        "outputId": "3b4dea28-4135-4d8d-a1fb-881161a8e58a"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXYAAADUCAYAAACI/Qg0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJztnX1wFHWe/989kw7MJMAEF09IQOVB\nEiMQJAL1Y++sUAIqKAF2QX+wxZbusud5dQdiFEruAH8i2UuhWOtt7caqfRJPwEUiDx7uKrh1y61a\noZKQoAi6oDDIGpURSCZkkvn+/hh66Onp54eZ7pnPq8qSTM90fzP59Kc/388jxxhjIAiCIHIGX7YX\nQBAEQdgLKXaCIIgcgxQ7QRBEjkGKnSAIIscgxU4QBJFjkGInCILIMUixEwRB5Bik2AmCIHIMUuwe\nYu3atdi6dauj15g6dSqOHTvm6DUIQgrJts2wPOfrr79mtbW1LBgMslGjRrFXXnlF8b133nknGzBg\nACsqKmJFRUXslltuMX0uLb755hsGgJ0+fZoxxtiXX37JRowYwbq7uxljjH3yyScsGAyyc+fOJT+z\nbds2Nnz4cPb555+rnre4uJi9++67Ka8vW7aMLViwgG3fvp0tXLjQ9LqlGPlOfvazn7EpU6awwsJC\ntnz5ctvWkK8Y+e4//PBDVlNTwwYPHszGjBnDXn/9dUPHjZALst3T08MeeughNmrUKFZcXMyqqqrY\nm2++qfh+O3WDHvJesT/wwANs8eLF7NKlS+x//ud/2ODBg1lHR4fse++880720ksv2XIuLQ4ePMhK\nSkqSP//Hf/wH+9GPfpTynsWLF7MnnniCMcbY//7v/7JQKMTef/99zXM/9thjbP78+cmfn376aXb7\n7bezrq4uFo1GWUlJScpNZQUj38muXbvY7t272T/+4z+SYrcBvd99LBZj48aNY1u2bGF9fX3snXfe\nYcFgkH388ce6jhslF2T78uXLbP369ezUqVOsv7+f7d27lxUXF7NTp07Jvt9O3aAHTyn2ixcvsh//\n+McsFAqxYcOGseeee87S+S5fvsx4nk8R0GXLlrEnn3xS9v1qit3oubR47rnnWE1NTfLnmpoa9vLL\nL6e858iRI2zIkCGsvb2d3XDDDWz79u3JY4888gh75JFHZM999uxZNnDgQPbJJ5+wnTt3srKyMhYO\nh5PH77rrLvab3/zG1LrFmP1OnnrqqbxT7NmU7fb2dlZUVMTi8XjytVmzZrF169bpOm6UXJBtOSZM\nmMB+//vfp71ut27Qg6d87LW1tRgzZgzOnz+P7du34/HHH8f58+eTx+fNm4dQKCT737x589LOd+LE\nCfj9ftxyyy3J1yZNmqTqh1u7di2+853vYMaMGXj33XctnUuNlpYWVFVVJX9ub2/H+PHjU95z++23\nY+rUqZg2bRoeeeQRLFmyJHns5z//OX7+85/Lnru0tBQPPvggHn30UfzTP/0T3njjDYwYMSJ5vKKi\nAm1tbWmfy8T3m69kU7aZTB9Axhg6Ojp0HTdKLsi2lL/97W84ceIEKisr045l4z4ocOzMNrNv3z4A\nwJNPPgkAmDlzJkpLS3HixAnccMMNKe/Ry+XLlzFkyJCU14YMGYJLly7Jvv+nP/0pbr31VhQWFmL7\n9u2477770NraijFjxhg+lxatra2oq6tL/hyJRDBo0KCU98Tjcfj9fvh8vuT3opfHHnsMEyZMwI4d\nO3D77benHBs0aBC++OKLtM84/f3mK9mW7fLyclx//fVoaGjAqlWrcOjQIfzpT39CTU2NruNGyQXZ\nFhOLxbB06VIsX74c5eXlacezcR94xmLfs2cP5s+fn/w5Ho/j22+/xd/93d+ZPmdxcTEuXryY8trF\nixfThExg2rRpGDRoEAYMGIDly5djxowZePPNN02dS40rV67go48+SrFqSkpK0gRh9erViEQiGDdu\nHF555RVD1+jt7cWAAQOwcOHCtGOXLl1CKBQyvG4pdn4nuUy2ZZvneTQ1NWH//v244YYbsGXLFixe\nvBhlZWW6jhshV2RbIB6P4wc/+AEKCwvx4osvyr4nG/eBZxT7+++/j+uuuy7588GDB/Gd73wnZQt3\nzz33oLi4WPa/e+65J+2ct9xyC/r6+nDy5Mnka21tbbLbKTk4jktuU62eS0xHRwf8fj8qKiqSr02c\nOBEnTpxI/vzLX/4Su3fvRlNTE5588kk0NDTIbpmVaGtrw2233YaCgvRN20cffYRJkyalvZ7p7zdf\ncINsT5w4EX/605/w9ddf46233sJf//pXTJ06VfdxveSKbAMJd9TDDz+Mv/3tb9i1axd4npd9X1bu\nA8e89zbS29vLAoEAq62tZdFolHV0dLBx48ax1157zfK5lyxZwh544AF2+fJl9uc//1kxWn3hwgV2\n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\n",
            "text/plain": [
              "\u003cFigure size 600x300 with 2 Axes\u003e"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.figure(figsize=(6,3))\n",
        "for i, rho in enumerate([0.5, 0.99]):\n",
        "  plt.subplot(1, 2, i + 1)\n",
        "  x, y = sample_correlated_gaussian(batch_size=500, dim=1, rho=rho)\n",
        "  plt.scatter(x[:, 0], y[:, 0])\n",
        "  plt.title(r'$\\rho=%.2f$,  $I(X; Y)=%.1f$' % (rho, rho_to_mi(1, rho)))\n",
        "  plt.xlim(-3, 3); plt.ylim(-3, 3);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "E_3UiG_O0LcM"
      },
      "source": [
        "### Training code"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "BEuLXbHdkodA"
      },
      "outputs": [],
      "source": [
        "def train_estimator(critic_params, data_params, mi_params):\n",
        "  \"\"\"Main training loop that estimates time-varying MI.\"\"\"\n",
        "  # Ground truth rho is only used by conditional critic\n",
        "  critic = CRITICS[mi_params.get('critic', 'concat')](rho=None, **critic_params)\n",
        "  baseline = BASELINES[mi_params.get('baseline', 'constant')]()\n",
        "  \n",
        "  opt = tf.keras.optimizers.Adam(opt_params['learning_rate'])\n",
        "  \n",
        "  @tf.function\n",
        "  def train_step(rho, data_params, mi_params):\n",
        "    # Annoying special case:\n",
        "    # For the true conditional, the critic depends on the true correlation rho,\n",
        "    # so we rebuild the critic at each iteration.\n",
        "    if mi_params['critic'] == 'conditional':\n",
        "      critic_ = CRITICS['conditional'](rho=rho)\n",
        "    else:\n",
        "      critic_ = critic\n",
        "    \n",
        "    with tf.GradientTape() as tape:\n",
        "      x, y = sample_correlated_gaussian(dim=data_params['dim'], rho=rho, batch_size=data_params['batch_size'])\n",
        "      mi = estimate_mutual_information(mi_params['estimator'], x, y, critic_, baseline, mi_params.get('alpha_logit', None))\n",
        "      loss = -mi\n",
        "  \n",
        "      trainable_vars = []\n",
        "      if isinstance(critic, tf.keras.Model):\n",
        "        trainable_vars += critic.trainable_variables \n",
        "      if isinstance(baseline, tf.keras.Model):\n",
        "        trainable_vars += baseline.trainable_variables\n",
        "      grads = tape.gradient(loss, trainable_vars)\n",
        "      opt.apply_gradients(zip(grads, trainable_vars))\n",
        "    return mi\n",
        "  \n",
        "  # Schedule of correlation over iterations \n",
        "  mis = mi_schedule(opt_params['iterations'])\n",
        "  rhos = mi_to_rho(data_params['dim'], mis)\n",
        "  \n",
        "  estimates = []\n",
        "  for i in range(opt_params['iterations']):\n",
        "    estimates.append(train_step(rhos[i], data_params, mi_params).numpy())\n",
        "\n",
        "  return np.array(estimates)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "hoRt2Xqy8TKV"
      },
      "source": [
        "Dataset, optimization, and critic parameters. Try experimenting with these."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "BWVf4SqJ2VSV"
      },
      "outputs": [],
      "source": [
        "data_params = {\n",
        "    'dim': 20,\n",
        "    'batch_size': 64,\n",
        "}\n",
        "\n",
        "critic_params = {\n",
        "    'layers': 2,\n",
        "    'embed_dim': 32,\n",
        "    'hidden_dim': 256,\n",
        "    'activation': 'relu',\n",
        "}\n",
        "\n",
        "opt_params = {\n",
        "    'iterations': 20000,\n",
        "    'learning_rate': 5e-4,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JjipPYg37_dp"
      },
      "source": [
        "Build a dictionary of the mutual information estimators to train and their parameters."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "wxHm0B6BSXW9"
      },
      "outputs": [],
      "source": [
        "critic_type = 'concat' # or 'separable'\n",
        "\n",
        "estimators = {\n",
        "    'NWJ': dict(estimator='nwj', critic=critic_type, baseline='constant'),\n",
        "    'TUBA': dict(estimator='tuba', critic=critic_type, baseline='unnormalized'),\n",
        "    'InfoNCE': dict(estimator='infonce', critic=critic_type, baseline='constant'),\n",
        "    'JS': dict(estimator='js', critic=critic_type, baseline='constant'),\n",
        "    'TNCE': dict(estimator='infonce', critic='conditional', baseline='constant'),\n",
        "    # Optimal critic for TUBA\n",
        "    #'TUBA_opt': dict(estimator='tuba', critic='conditional', baseline='gaussian')\n",
        "}\n",
        "\n",
        "# Add interpolated bounds\n",
        "def sigmoid(x):\n",
        "  return 1/(1. + np.exp(-x))\n",
        "for alpha_logit in [-5., 0., 5.]:\n",
        "  name = 'alpha=%.2f' % sigmoid(alpha_logit)\n",
        "  estimators[name] = dict(estimator='interpolated', critic=critic_type,\n",
        "                          alpha_logit=alpha_logit, baseline='unnormalized')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "lsJmWnvr8LsV"
      },
      "source": [
        "Train each estimator and store mutual information estimates (this takes ~2 minutes on a modern GPU)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "colab": {
          "height": 153
        },
        "colab_type": "code",
        "executionInfo": {
          "elapsed": 273274,
          "status": "ok",
          "timestamp": 1561485923767,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "ToS0lWq58K9b",
        "outputId": "a6c6a57e-f0e2-4c82-9341-a0e84d918f72"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Training NWJ...\n",
            "Training TUBA...\n",
            "Training InfoNCE...\n",
            "Training JS...\n",
            "Training TNCE...\n",
            "Training alpha=0.01...\n",
            "Training alpha=0.50...\n",
            "Training alpha=0.99...\n"
          ]
        }
      ],
      "source": [
        "estimates = {}\n",
        "for estimator, mi_params in estimators.items():\n",
        "  print(\"Training %s...\" % estimator)\n",
        "  estimates[estimator] = train_estimator(critic_params, data_params, mi_params)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QpCGVeUc0Tdc"
      },
      "source": [
        "### Results"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "colab": {
          "height": 442
        },
        "colab_type": "code",
        "executionInfo": {
          "elapsed": 1978,
          "status": "ok",
          "timestamp": 1561486375196,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "1fDDK1rAiZFT",
        "outputId": "eb57d1ed-0c84-4aff-e83e-de6d35e42d30"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nvZO9k72TvQcjW0dg165d7IorrpBeP/zww+zhhx/O2PUi/XAaGxtZb28vY8z/BTY2NjLGGNu6dSt7\n/vnnw/Z7/vnn2datW6XtM/eLRWdnZ4ihpuvavb29rKmpSdo+c79ExxPthzPze7niiivYrl27on5/\ngiCwwsJC5vF4GGPh33M8Nm3axP7yl7/k/PPJBNm0ebL32OMhe888+WTvjMnL5snesw/ZO9n7TORi\n77JNDerp6UFVVZX0urKyEj09PRm7HsdxuOKKK7BixQps374dANDX14eysjIAQFlZGc6fPx9zbOkc\nc7qu3dPTg8rKyrSM6cknn0RbWxtuu+02KXSV7HgGBwdhtVqhVCqTHk9XVxc+/PBDrF69Wpafz2zJ\nps2TvceH7D2z5LO9p/P66fpOyd4zC9m7vL5TsvdpZOsIsAh5TRzHZex67733Hg4cOICXX34ZTz31\nFN55552kx5aNMSd77XSN6Y477kBHRwf+/ve/o6ysDHfffXdWx+NwOLB582Y8/vjjMJvNUffL1eeT\nDrI5FrL32JC9Zx6y9/RcPx3jInvPPGTv6bk+2Xv6xyNbR6CyshLd3d3S6zNnzqC8vDxj1xPPXVxc\njOuuuw579uxBSUkJzp49CwA4e/YsiouLY44tnWNO17UrKytx5syZWY+ppKQECoUCPM/jK1/5Cvbs\n2ZPSeOx2O0ZGRuD1ehMej8fjwebNm3HLLbfg+uuvl+Xnkw6yafNk7/HHQ/aeWfLZ3gF5fadk75mH\n7F0+3ynZ+wziJg/lCI/Hw2pqatjJkyel4oxDhw5l5FoOh4ONjY1J/77ooovYyy+/zL797W+HFHDc\nc889jDHGXnrppZACjpUrVzLG/AUc1dXVbGhoiA0NDbHq6mo2ODiY0Bhm5rCl89rt7e3s/fffl4pH\nduzYkfR4xPw1xhh77LHH2I033sgYY+zQoUMhxTU1NTXM6/XG/P5uuOGGkOKap556Kuo4BEFgt956\nK/vWt74Vsj3Xn08myJbNk73HHw/Ze+bJJ3tnTF42T/aefcjeyd7lau+ydQQY81dMNzQ0sNraWvbQ\nQw9l7DodHR2sra2NtbW1scWLF0vXGhgYYBs2bGD19fVsw4YN0gctCAL7+te/zmpra1lLSwvbu3ev\ndK6f/exnrK6ujtXV1bGf//znCV3/pptuYqWlpUypVLKKigr2zDPPpPXae/fuZUuWLGG1tbXsG9/4\nBhMEIenxfP7zn2ctLS2stbWVXXvttSE/pIceeojV1tayxsbGkAr1aN9fR0cHW7lyJaurq2M33HAD\nc7lcUcfy7rvvMgCstbWVLV26lC1dupTt2LEjp59PJsmGzZO9xx8P2Xt2yAd7Z0xeNk/2TvZO9k72\nHgzHWA5FdQmCIAiCIAiCyAmyrREgCIIgCIIgCCJzkCNAEARBEARBEHkIOQIEQRAEQRAEkYeQI0AQ\nBEEQBEEQeQg5AgRBEARBEASRh5AjIHMef/xxOJ3OXA+DIAiCIAiCmGeQfKjMqa6uxr59+2C323M9\nFIIgCIIgCGIeQREBGTExMYFrrrkGS5cuRUtLCx588EH09vZi/fr1WL9+PQDgL3/5Cy666CIsX74c\nW7ZsgcPhAOB3GO69916sWrUKq1atwokTJwAAv//979HS0oKlS5fikksuydnfRhAEQRAEQcgLcgRk\nxCuvvILy8nIcPHgQhw4dwl133YXy8nK8+eabePPNNzEwMICHHnoIr732Gg4cOID29nY89thj0vFm\nsxl79uzBN7/5Tdx1110AgO9973t49dVXcfDgQbz44ou5+tMIgiAIgiAImUGOgIxobW3Fa6+9hnvv\nvRfvvvsuLBZLyPu7d+/GkSNHsGbNGixbtgzPPvssTp06Jb1/8803S/9///33AQBr1qzBl770Jfzn\nf/4nfD5f9v4YgiAIgiAIQtYocz0AYprGxkbs378fO3fuxH333Ycrrrgi5H3GGDZu3IgXXngh4vEc\nx4X9+6c//Sk++OAD7NixA8uWLcPf//53FBYWZu6PIAiCIAiCIOYEFBGQEb29vdDr9fj85z+Pb3/7\n2zhw4ABMJhPGx8cBABdeeCHee+89Kf/f6XTi2LFj0vG//e1vpf9fdNFFAICOjg6sXr0a3/ve92C3\n29Hd3Z3lv4ogCIIgCIKQIxQRkBH/+Mc/cM8994DneahUKvzkJz/B+++/j6uuugplZWV488038ctf\n/hI333wz3G43AOChhx5CY2MjAMDtdmP16tUQBEGKGtxzzz04fvw4GGO47LLLsHTp0pz9fQRBEARB\nEIR8IPnQeQLJjBIEQRAEQRDJQKlBBEEQBEEQBJGHUESAIAiCIAiCIPIQiggQBEEQBEEQRB5CjgBB\nEARBEARB5CHkCBAEQRAEQRBEHkKOAEEQBEEQBEHkIeQIEARBEARBEEQe8v8DOVEOrH08XmYAAAAA\nSUVORK5CYII=\n",
            "text/plain": [
              "\u003cFigure size 1080x600 with 8 Axes\u003e"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Smooting span for Exponential Moving Average\n",
        "EMA_SPAN = 200\n",
        "\n",
        "# Ground truth MI\n",
        "mi_true = mi_schedule(opt_params['iterations'])\n",
        "\n",
        "# Names specifies the key and ordering for plotting estimators\n",
        "names = np.sort(list(estimators.keys()))\n",
        "lnames = list(map(lambda s: s.replace('alpha', '$\\\\alpha$'), names))\n",
        "\n",
        "nrows = min(2, len(estimates))\n",
        "ncols = int(np.ceil(len(estimates) / float(nrows)))\n",
        "fig, axs = plt.subplots(nrows, ncols, figsize=(2.7 * ncols, 3 * nrows)) \n",
        "if len(estimates) == 1:\n",
        "  axs = [axs]\n",
        "axs = np.ravel(axs)\n",
        "  \n",
        "for i, name in enumerate(names):\n",
        "  plt.sca(axs[i])\n",
        "  plt.title(lnames[i])\n",
        "  # Plot estimated MI and smoothed MI\n",
        "  mis = estimates[name]  \n",
        "  mis_smooth = pd.Series(mis).ewm(span=EMA_SPAN).mean()\n",
        "  p1 = plt.plot(mis, alpha=0.3)[0]\n",
        "  plt.plot(mis_smooth, c=p1.get_color())\n",
        "  # Plot true MI and line for log(batch size)\n",
        "  plt.plot(mi_true, color='k', label='True MI')\n",
        "  estimator = estimators[name]['estimator']\n",
        "  if 'interpolated' in estimator or 'nce' in estimator:\n",
        "    # Add theoretical upper bound lines\n",
        "    if 'interpolated' in estimator:\n",
        "      log_alpha = -np.log( 1+ tf.exp(-estimators[name]['alpha_logit']))\n",
        "    else:\n",
        "      log_alpha = 1.\n",
        "    plt.axhline(1 + np.log(data_params['batch_size']) - log_alpha, c='k', linestyle='--', label=r'1 + log(K/$\\alpha$)' )\n",
        "  plt.ylim(-1, mi_true.max()+1)\n",
        "  plt.xlim(0, opt_params['iterations'])\n",
        "  if i == len(estimates) - ncols:\n",
        "    plt.xlabel('steps')\n",
        "    plt.ylabel('Mutual information (nats)')\n",
        "plt.legend(loc='best', fontsize=8, framealpha=0.0)\n",
        "plt.gcf().tight_layout();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ROkb4-mMr4_w"
      },
      "source": [
        "## Structured Bounds\n",
        "\n",
        "The structured lower bounds use known conditional and learned marginal distributions to lower and upper bound mutual information. Check back soon for some more examples with these bounds!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4FtDiO6jVbEB"
      },
      "outputs": [],
      "source": [
        "def log_prob_pairs(dists, samples):\n",
        "  if isinstance(dists, (tfd.Normal, tfd.MultivariateNormalDiag)):\n",
        "    return gaussian_log_prob_pairs(dists, samples)\n",
        "  batch_size = tf.shape(samples)[0]\n",
        "  multiples = [1] * (1 + len(samples.get_shape().as_list()))\n",
        "  multiples[1] = tf.shape(samples)[0]\n",
        "  samples_tiled = tf.tile(samples[:, None], multiples)\n",
        "  # Compute log probs, size [batch_size, batch_size]\n",
        "  log_probs = dists.log_prob(samples_tiled)\n",
        "  return log_probs\n",
        "\n",
        "def variational_upper_bound(conditional_dist, marginal_dist, samples):\n",
        "  \"\"\"Variational upper bound on mutual information.\n",
        "\n",
        "  Args:\n",
        "    conditional_dist: true conditional density, p(y|x)\n",
        "    marginal_dist: approximate marginal density, m(y)\n",
        "    samples: samples from the conditional distribution p(y|x)\n",
        "\n",
        "  Returns:\n",
        "    scalar, upper bound on mutual information\n",
        "  \"\"\"\n",
        "  return tf.reduce_mean(conditional_dist.log_prob(samples) -\n",
        "                        marginal_dist.log_prob(samples))\n",
        "\n",
        "\n",
        "def minibatch_upper_bound(conditional_dist, samples):\n",
        "  \"\"\"Minibatch upper bound on mutual information.\n",
        "\n",
        "  Args:\n",
        "    conditional_dist: approximate conditional density, e(y|x)\n",
        "    samples: samples from conditional_dist\n",
        "\n",
        "  Returns:\n",
        "    scalar, upper bound on mutual information\n",
        "  \"\"\"\n",
        "  log_probs = log_prob_pairs(conditional_dist, samples)\n",
        "  # Batch marginal holds out self (along diagonal), and averages over\n",
        "  # all other elements in the batch.\n",
        "  mask = tf.eye(tf.shape(samples)[0])\n",
        "  log_prob_marginal = tf.reduce_mean(reduce_logmeanexp_nodiag(log_probs, axis=1))\n",
        "  log_prob_cond = tf.reduce_mean(tf.linalg.tensor_diag_part(log_probs))\n",
        "  return log_prob_cond - log_prob_marginal\n",
        "\n",
        "def minibatch_lower_bound(conditional_dist, samples):\n",
        "  \"\"\"Minibatch lower bound on mutual information.\n",
        "\n",
        "  Args:\n",
        "    conditional_dist: approximate conditional density, e(y|x)\n",
        "    samples: samples from conditional_dist\n",
        "\n",
        "  Returns:\n",
        "    scalar, lower bound on mutual information\n",
        "  \"\"\"\n",
        "  batch_marginal_dist = tfd.MixtureSameFamily(\n",
        "      mixture_distribution=tfd.Categorical(logits=tf.zeros(conditional_dist.batch_shape)),\n",
        "      components_distribution=conditional_dist)\n",
        "  return variational_upper_bound(conditional_dist, batch_marginal_dist, samples)"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [
        "ULndVKL12doD",
        "IfHEX-0eaOHP",
        "KgnZ2S_KF5-y",
        "wOraxkkSOb-6",
        "ROkb4-mMr4_w"
      ],
      "last_runtime": {
        "build_target": "//learning/brain/python/client:colab_notebook_py3",
        "kind": "private"
      },
      "name": "Variational Bounds of Mutual Information Demo",
      "provenance": [],
      "toc_visible": true,
      "version": "0.3.2"
    },
    "kernelspec": {
      "display_name": "Python 2",
      "name": "python2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
